package com.css.apps.base.user.action;

import com.css.apps.base.dict.service.DictMan;
import com.css.apps.base.user.model.SUser;
import com.css.apps.base.user.po.UserFamilyPo;
import com.css.core.configuration.Environment;
import com.css.db.query.QueryCache;
import com.css.util.*;
import com.opensymphony.webwork.ServletActionContext;
import com.opensymphony.xwork.Action;
import org.apache.commons.io.IOUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.poi.POIXMLDocument;
import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFTable;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@SuppressWarnings("serial")
public class ExportUser extends UserAction {

	private static Log log = LogFactory.getLog(ExportUser.class);

	private final static String templateFilePath = "/userTemplator.docx";
	private final static String tempZipFold = "/tempZipFold/";  //批量导出存放过程文件路径
	private String ids;

    @Override
    protected String userGo() {
        try {
            if(StringHelper.isEmpty(ids)){
                result = Ajax.JSONResult(Environment.RESULT_CODE_ERROR, Messages.getString("systemMsg.fieldEmpty"));
                return Action.ERROR;
            }
            HttpServletResponse response = resetHttpServletResponse();
            List<String> userIds = StringHelper.strToList(ids);
            //支持单个导出和批量导出 （多个进行批量导出）
            String backResult = userIds.size()==1 ? exportSingle(response,userIds.get(0)) : exportBatch(response,userIds);
            return  backResult;
        }catch (Exception e){
            result = Ajax.JSONResult(Environment.RESULT_CODE_ERROR, Messages.getString("systemMsg.exception"));
            return Action.ERROR;
        }
    }

    /**
     * 批量导出
     * @param response
     * @param userIds
     * @return
     */
    private String exportBatch(HttpServletResponse response, List<String> userIds) {
        OutputStream out = null;
        try {
            String randNum = new SimpleDateFormat("HH.mm.ss").format(new Date());
            //创建临时文件夹
            String srcFoldPath = tempZipFold + "任免审批表(" +randNum +")";
            File srcFold = new File(srcFoldPath);
            if(!srcFold.exists()){
                srcFold.mkdirs();
            }
            for (String userId : userIds) {
                try {
                    SUser iuser = QueryCache.get(SUser.class,userId);
                    if(iuser==null){
                        System.out.println("uuid为：" + userId + "的用户无法导出！");
                        continue;
                    }
                    //数据构建
                    Map<String, String> params = buildParams(iuser);
                    //导入模板文件
                    OPCPackage pack = POIXMLDocument.openPackage(this.getClass().getResource(templateFilePath).getPath());
                    XWPFDocument document = new XWPFDocument(pack);
                    //表格标记替换
                    List<XWPFTable> tables = document.getTables();
                    new WordUtil().replaceInTables(tables, params);
                    //输出到文件(有重名的则增加序号加以区别)
                    String fileName = iuser.getOrgName()+" - "+iuser.getRealName();
                    File file = createExcelFile(srcFoldPath,fileName+".docx");
                    out =new FileOutputStream(file);
                    document.write(out);
                    out.flush();
                } catch (Exception e) {
                    e.printStackTrace();
                    continue;
                }finally {
                    IOUtils.closeQuietly(out);
                }
            }
            //压缩为zip文件
            String outZipFilePath = tempZipFold + randNum + ".zip";
            File zipFile = new File(outZipFilePath);
            FileZipUtil.zipCompress(srcFoldPath,outZipFilePath);
            InputStream in = null;
            try {
                response.setHeader("Content-disposition","attachment;filename=\"" + new String("任免审批表.zip".getBytes("gb2312"), "ISO8859-1") + "\"");
                //输出zip文件到response
                out =response.getOutputStream();
                in = new FileInputStream(outZipFilePath);
                int length = 0;
                byte[] byteBuffer = new byte[1024];
                while ((length=in.read(byteBuffer)) != -1){
                    out.write(byteBuffer,0,length);
                }
                out.flush();
            }catch (Exception e){
                e.printStackTrace();
                return Action.ERROR;
            }finally {
                IOUtils.closeQuietly(in);
                IOUtils.closeQuietly(out);
            }
            //清理生成的fold 和 zip文件
            if(zipFile.exists()){
                zipFile.delete();
            }
            if(srcFold.exists()){
                deleteDir(srcFold);
            }
        }catch (Exception e){
            e.printStackTrace();
            return Action.ERROR;
        }
        return Action.SUCCESS;
    }

    /**
     * 生成审批表文件（支持同名标注功能）
     * @param srcFoldPath
     * @param fileName
     * @return
     */
    private File createExcelFile(String srcFoldPath, String fileName) {
        File file = new File(srcFoldPath,fileName);
        while (true){
            if(!file.exists()){
                break;
            }
            fileName = getNewFileName(fileName);
            file = new File(srcFoldPath,fileName);
        }
        return file;
    }

    /**
     * 获取新文件名
     * @param fileName
     * @return
     */
    private String getNewFileName(String fileName){
        if(fileName.replaceAll(".docx","").trim().matches("\\D*\\d+")){
            int  diffNum = Integer.parseInt(fileName.replaceAll("\\D*",""));
            fileName = fileName.replaceAll(String.valueOf(diffNum),String.valueOf(diffNum + 1));
        }else{
            fileName = fileName.replaceAll(".docx","1.docx");
        }
        return  fileName;
    }

    /**
     * 重置请求
     * @return
     */
    private HttpServletResponse resetHttpServletResponse(){
        //设置响应
        HttpServletResponse response = ServletActionContext.getResponse();
        response.reset();
        response.setHeader("content-type", "application/octet-stream");
        response.setContentType("application/octet-stream");
        response.setCharacterEncoding("UTF-8");
        // response.setHeader("Pragma", "No-cache");
        // response.setDateHeader("Expires", 0);
        // response.setContentType("application/octet-stream;charset=UTF-8");
        return response;
    }

    /**
     * 单个导出
     * @param response
     * @param userId
     * @return
     */
    private String exportSingle(HttpServletResponse response,String userId){
        OutputStream out = null;
        try {
            SUser iuser = QueryCache.get(SUser.class,userId);
            if(iuser==null){
                result = Ajax.JSONResult(Environment.RESULT_CODE_ERROR, Messages.getString("systemMsg.fieldEmpty"));
                return Action.ERROR;
            }
            String fileName = iuser.getOrgName()+" - "+iuser.getRealName();
            response.setHeader("Content-disposition","attachment;filename=\"" + new String((fileName+".docx").getBytes("gb2312"), "ISO8859-1") + "\"");
            //数据构建
            Map<String, String> params = buildParams(iuser);
            //导入模板文件
            OPCPackage pack = POIXMLDocument.openPackage(this.getClass().getResource(templateFilePath).getPath());
            XWPFDocument document = new XWPFDocument(pack);
            //表格标记替换
            List<XWPFTable> tables = document.getTables();
            new WordUtil().replaceInTables(tables, params);
            out = response.getOutputStream();
            document.write(out);
            out.flush();
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            setMessage(Messages.getString("systemMsg.failed"));
            e.printStackTrace();
            return Action.ERROR;
        }finally {
            IOUtils.closeQuietly(out);
        }
        return Action.SUCCESS;
    }

    /**
     * 根据用户id构建参数集
     * @param iuser
     * @return
     */
    private Map<String, String> buildParams(SUser iuser){
        Map<String, String> params = new HashMap<>();
        params.put("${name}", checknull(iuser.getRealName()));
        params.put("${nation}",iuser.getNation());
        params.put("${sex}",DictMan.getDictName("d_sex",checknull(iuser.getSex())));
        params.put("${birthday}",checkDate(iuser.getBirthday()));
        params.put("${nativeplace}",checknull(iuser.getNativeplace()));
        params.put("${birthplace}",checknull(iuser.getBirthplace()));
        params.put("${health}",checknull(iuser.getHealth()));
        params.put("${professiontech_duty}",checknull(iuser.getProfessiontech_duty()));
        params.put("${skill}",checknull(iuser.getSkill()));
        params.put("${full_time_education}",checknull(iuser.getFull_time_education()));
        params.put("${full_time_school_major}",checknull(iuser.getFull_time_school_major()));
        params.put("${on_the_job_education}",checknull(iuser.getOn_the_job_education()));
        params.put("${on_the_job_school_major}",checknull(iuser.getOn_the_job_school_major()));
        params.put("${current_duty}",checknull(iuser.getCurrent_duty()));
        params.put("${joinpartytime}",checkDate(iuser.getJoinpartytime()));
        params.put("${joinworktime}",checkDate(iuser.getJoinworktime()));
        params.put("${resume}", TagReverse(iuser.getResume()));
        params.put("${reward_and_punish}", TagReverse(iuser.getReward_and_punish()));
        params.put("${examine_conclusion}",TagReverse(iuser.getExamine_conclusion()));
        List<UserFamilyPo> familyList = new QueryCache("from UserFamilyPo a where a.userId =:userId ").setParameter("userId",iuser.getUuid()).list();
        for(int i=0;i<familyList.size();i++){
            UserFamilyPo userFamilyPo = familyList.get(i);
            String appellation =  userFamilyPo.getAppellation();
            String membername = userFamilyPo.getMembername();
            int age = getAge(userFamilyPo.getBirthday());
            String politicallandscape = userFamilyPo.getPoliticallandscape();
            String unitandposition = userFamilyPo.getUnitandposition();
            int index = i+1;
            params.put("${appellation"+ index +"}",appellation);
            params.put("${membername"+ index +"}",membername);
            params.put("${politicallandscape"+ index +"}",politicallandscape);
            params.put("${unitandposition"+ index +"}",unitandposition);
            params.put("${age"+ index +"}",age==0?"":String.valueOf(age));
        }
        //将其余家庭信息制空
        if(familyList.size()<7){
            for (int i=familyList.size()+1;i<=7;i++){
                int index = i;
                params.put("${appellation"+ index +"}","");
                params.put("${membername"+ index +"}","");
                params.put("${politicallandscape"+ index +"}","");
                params.put("${unitandposition"+ index +"}","");
                params.put("${age"+ index +"}","");
            }
        }
        Calendar calendar = Calendar.getInstance();
        int curyear = calendar.get(Calendar.YEAR);
        int curmonth = calendar.get(Calendar.MONTH) + 1;
        int curday = calendar.get(Calendar.DAY_OF_MONTH);
        params.put("${curyear}", String.valueOf(curyear));
        params.put("${curmonth}",String.valueOf(curmonth));
        params.put("${curday}",String.valueOf(curday));
        return  params;
    }

    /**
     * 根据生日计算年龄（周岁）
     * @param birthDay
     * @return
     * @throws Exception
     */
    private int getAge(String birthDay){
        int age = 0;
        try {
            if(StringHelper.isEmpty(birthDay)){
                return 0;
            }
            Date birthDayToDate = new SimpleDateFormat("yyyy-MM").parse(birthDay);
            Calendar cal = Calendar.getInstance();
            if (cal.before(birthDayToDate)) {//出生日期晚于当前时间，无法计算
                throw new IllegalArgumentException("The birthDay is before Now.It's unbelievable!");
            }
            int yearNow = cal.get(Calendar.YEAR); //当前年份
            int monthNow = cal.get(Calendar.MONTH); //当前月份
            int dayOfMonthNow = cal.get(Calendar.DAY_OF_MONTH);//当前日期
            cal.setTime(birthDayToDate);
            int yearBirth = cal.get(Calendar.YEAR);
            int monthBirth = cal.get(Calendar.MONTH);
            int dayOfMonthBirth = cal.get(Calendar.DAY_OF_MONTH);
            age = yearNow - yearBirth;  //计算整岁数
            if (monthNow <= monthBirth) {
                if (monthNow == monthBirth) {
                    if (dayOfMonthNow < dayOfMonthBirth) age--;//当前日期在生日之前，年龄减一
                }else{
                    age--;//当前月份在生日之前，年龄减一
                }
            }
        }catch (Exception e){
           //nothing to do
        }
        return age;
    }

    /**
     * 递归删除目录下的所有文件及子目录下所有文件
     * @param dir 将要删除的文件目录
     */
    private static boolean deleteDir(File dir) {
        if (dir.isDirectory()) {
            String[] children = dir.list();
            for (int i=0; i<children.length; i++) {
                boolean success = deleteDir(new File(dir, children[i]));
                if (!success) {
                    return false;
                }
            }
        }
        // 目录此时为空，可以删除
        return dir.delete();
    }

    /**
     * 特殊字符转换
     * @param sSource
     * @return
     */
    private String TagReverse(String sSource) {
        if (StringHelper.isEmpty(sSource)) {
            return "";
        } else {
            Pattern p = null;
            Matcher m = null;
            String s = null;
            String sTmp = null;
            StringBuffer sb = null;
            p = Pattern.compile("(<br/>|\\&lt;|\\&gt;)", 2);
            m = p.matcher(sSource);

            for(sb = new StringBuffer(); m.find(); m.appendReplacement(sb, s)) {
                sTmp = m.group().toLowerCase();
                if (sTmp.equals("<br/>")) {
                    s = "\r\n ";
                } else if (sTmp.equals("&lt;")) {
                    s = "<";
                } else if (sTmp.equals("&gt;")) {
                    s = ">";
                }
            }

            m.appendTail(sb);
            return sb.toString();
        }
    }

    private String checknull(String field){
        return StringHelper.isEmpty(field) ? "" : field.trim();
    }

    private String checkDate(Date date){
        return date == null ? "" : new SimpleDateFormat("yyyy.M").format(date).toString();
    }

    private String checkbirth(Date birthDay){
        return birthDay==null ? "" : new SimpleDateFormat("yyyy.M.d").format(birthDay).toString();
    }

    public String getIds() {
        return ids;
    }

    public void setIds(String ids) {
        this.ids = ids;
    }
}
